﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MatlabIG
{
    class Particles
    {
        VertexBuffer vertexbuffer;
        BasicEffect basicEffect;
        Texture2D plasmaTexture;
        const int MaxParticles = 10000;
        Random rnd = new Random();

        struct SParticle
        {
            public Vector3 position;
            public Vector3 vector;
            public double timeToLive;
            public Color color;
        }

        List<SParticle> ParticleArray = new List<SParticle>();

        public void Init()
        {
            ParticleArray.Clear();

            // init basic effect
            basicEffect = new BasicEffect(Globals.Graphics.GraphicsDevice);

            //plasmaTexture = Globals.Content.Load<Texture2D>("plasma");

            vertexbuffer = new VertexBuffer(Globals.Graphics.GraphicsDevice, typeof(VertexPositionColor), MaxParticles*2, BufferUsage.None);                
        }


        public void AddParticleRandom(Vector3 pos, Vector3 dir, double ttl, Color color)
        {
            double x=(rnd.NextDouble()-0.5)/3;
            double y=(rnd.NextDouble()-0.5)/3;
            double z=(rnd.NextDouble()-0.5)/3;

            AddParticle(pos, dir + new Vector3((float)x, (float)y, (float)z), ttl, color);
        }

        public void AddParticle(Vector3 pos, Vector3 dir, double ttl, Color color)
        {
            if (ParticleArray.Count >= MaxParticles) return; // no more room for new particles
            SParticle particle = new SParticle();
            particle.position = pos;
            particle.vector = dir;
            particle.timeToLive = ttl;
            particle.color = color;

            ParticleArray.Add(particle);
        }

        public void Update(float time)
        {
            List<SParticle> pa = new List<SParticle>(); // new list

            for(int i=0; i!=ParticleArray.Count; i++)
            {
                SParticle p = ParticleArray[i];
                p.position = p.position + Vector3.Multiply(p.vector,time);
                p.timeToLive -= time;
                if (p.timeToLive > 0)
                {
                    pa.Add(p);
                }
            }

            ParticleArray = pa;
        }

        public void Draw()
        {
            // fill vertex buffer
            VertexPositionColor[] vertices = new VertexPositionColor[ParticleArray.Count*2];
            for (int i = 0; i != ParticleArray.Count; i++)
            {
                SParticle p = ParticleArray[i];
                vertices[i*2].Position = p.position;
                vertices[i*2].Color = p.color;
                vertices[i*2+1].Position = p.position + new Vector3(0, 0, 0.001f); // draw smal lines (XXX: Add quads/billboarding in Shader)
                vertices[i*2+1].Color = p.color;
            }
            vertexbuffer.SetData(vertices);

            // set effect parameters
            basicEffect.World = Matrix.Identity;
            basicEffect.View = Globals.ViewMat;
            basicEffect.Projection = Globals.ProjectionMat;
            basicEffect.LightingEnabled = false;
            basicEffect.VertexColorEnabled = true;

            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Apply();
                Globals.Graphics.GraphicsDevice.SetVertexBuffer(vertexbuffer);
                Globals.Graphics.GraphicsDevice.DrawPrimitives(PrimitiveType.LineList, 0, ParticleArray.Count);
            }
        }
    }
}
